package com.panda.web.excel.utils;

import com.panda.web.excel.domain.OrderExcel;

import org.apache.logging.log4j.util.Supplier;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Component;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.*;

@Component
public class ExcelUtils {



    /**
     * 出库单独导出
     *
     * @param response
     */
    public void exportExcel(HttpServletResponse response, List<OrderExcel> excelList) {
        try (Workbook workbook = new XSSFWorkbook()) { // 创建 Workbook 和 Sheet
            Sheet sheet = workbook.createSheet("订单" + "_" + UUID.randomUUID());

            String[] headers = {
                    "用户昵称", "学生姓名", "毕业类型", "学历", "专业", "产品名称",
                    "实际缴费", "来源", "支付状态", "支付时间", "退款状态", "订单类型"
            };
            //样式
            CellStyle titleCellStyle = workbook.createCellStyle();
            // 设置字体
            Font detailFont = workbook.createFont();
            detailFont.setFontName("宋体"); // 字体
            detailFont.setFontHeightInPoints((short) 10); // 字体大小
            titleCellStyle.setFont(detailFont);
//            titleCellStyle.setWrapText(true); // 自动换行
            // 创建标题行
            addUsingTitleRow(sheet, titleCellStyle, "订单列表", 11);
            // 生成标题行
            Row headerRow = sheet.createRow(1);
            headerRow.setHeightInPoints(27);
            createHeaderCells(headerRow, headers); // 更新后的创建标题行方法
            // 设置列宽（自动根据数据长度调整）
            for (int i = 0; i < 12; i++) { // 假设有16列，如果列数不同，调整此值
                sheet.autoSizeColumn(i);
            }
            // 创建数字格式的 CellStyle
            CreationHelper createHelper = workbook.getCreationHelper();
            CellStyle numberCellStyle = workbook.createCellStyle();
            numberCellStyle.setDataFormat(createHelper.createDataFormat().getFormat("#,##0.00"));

//            // 收集需要合并的数据
//            int rowNum = 2;
//            for (ShipmentsExcel excel : excelList) {
//                if (excel == null) {
//                    continue;
//                }
//                Row row = sheet.createRow(rowNum);
//                fillShipmentsRowWithContractData(row, excel, numberCellStyle); // 将数据填充到当前行
//                rowNum++; // 在创建新行后递增行号
//            }
            // 收集需要合并的数据
            int rowNum = 2;
            // 记录每个合同ID对应的所有行号
            Map<String, List<Integer>> contractRows = new HashMap<>();
            for (OrderExcel excel : excelList) {
                if (excel == null) {
                    continue;
                }
                Row row = sheet.createRow(rowNum);
                fillNewDeliveryRowWithContractData(row, excel, numberCellStyle); // 将数据填充到当前行
                String key = String.valueOf(excel.getId()); // 获取合同ID作为唯一标识
                contractRows.computeIfAbsent(key, k -> new ArrayList<>()).add(rowNum); // 如果该合同ID第一次出现，初始化其行号列表
                rowNum++; // 在创建新行后递增行号
            }

            // 在所有数据遍历完成后，根据记录的行号进行合并操作
            for (Map.Entry<String, List<Integer>> entry : contractRows.entrySet()) {
                String key = entry.getKey();
                System.out.println("Processing contract ID: " + key);
                List<Integer> rows = entry.getValue();

                if (rows.size() > 1) { // 只有当存在多行时才需要合并
                    int startRow = rows.get(0); // 第一行作为起始行
                    int endRow = rows.get(rows.size() - 1); // 最后一行作为结束行

                    // 执行列合并操作
                    for (int colIndex : new int[]{0, 1, 2, 3, 4,5,6, 7,8,9,10,11}) { // 根据实际需求调整列索引
                        mergeColumns(sheet, startRow, endRow, colIndex);
                    }
                }
            }
            // 生成合计行
            generateNewDeliveryTotalRow(sheet, excelList, numberCellStyle, rowNum);
            // 设置数据行的行高
            setRowHeightForDataRows(sheet, 2, (int) rowNum, (short) 18);
            //设置宽度
            adjustColumnWidths(sheet, 1, headers);
            // 给所有单元格添加边框
            addBordersToAllCells(sheet, titleCellStyle);
            // 设置响应头
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-Disposition", "attachment; filename=contracts.xlsx");

            // 将 Workbook 写入到 HTTP 响应中
            try (ServletOutputStream outputStream = response.getOutputStream()) {
                workbook.write(outputStream);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }



    /**
     * 根据组合键合并指定列
     */
    private void mergeComboColumns(Sheet sheet, List<Integer> rows, Map<Integer, String> rowComboKeys, int[] columns) {
        if (rows.size() < 2) return;

        // 按行号排序确保顺序
        Collections.sort(rows);
        int start = 0;
        String currentKey = rowComboKeys.get(rows.get(start));

        for (int i = 1; i < rows.size(); i++) {
            int rowNum = rows.get(i);
            String key = rowComboKeys.get(rowNum);
            if (!key.equals(currentKey)) {
                // 合并从start到i-1的行
                mergeColumnsForRange(sheet, rows.subList(start, i), columns);
                start = i;
                currentKey = key;
            }
        }
        // 处理最后一段
        mergeColumnsForRange(sheet, rows.subList(start, rows.size()), columns);
    }

    /**
     * 合并指定行范围内的列
     */
    private void mergeColumnsForRange(Sheet sheet, List<Integer> rowNumbers, int[] columns) {
        if (rowNumbers.size() < 2) return; // 不需要合并单一行

        int startRow = rowNumbers.get(0);
        int endRow = rowNumbers.get(rowNumbers.size() - 1);

        for (int col : columns) {
            boolean hasContent = false;
            // 检查是否有内容，避免合并空白单元格
            for (int r = startRow; r <= endRow; r++) {
                Row row = sheet.getRow(r);
                if (row != null && row.getCell(col) != null && !isCellEmpty(row.getCell(col))) {
                    hasContent = true;
                    break;
                }
            }
            if (hasContent) {
                sheet.addMergedRegion(new CellRangeAddress(startRow, endRow, col, col));
            }
        }
    }

    /**
     * 判断单元格是否为空
     */
    private boolean isCellEmpty(Cell cell) {
        if (cell == null) return true;
        CellType type = cell.getCellType();
        if (type == CellType.STRING) {
            return cell.getStringCellValue().trim().isEmpty();
        } else if (type == CellType.NUMERIC) {
            return false;
        } else if (type == CellType.BOOLEAN) {
            return false;
        } else if (type == CellType.ERROR) {
            return false;
        } else {
            return true;
        }
    }






    //新出库
    private void fillNewDeliveryRowWithContractData(Row row, OrderExcel excel, CellStyle numberCellStyle) {
        row.createCell(0).setCellValue(safeGet(excel::getNickName, ""));
        row.createCell(1).setCellValue(safeGet(excel::getName, ""));
        row.createCell(2).setCellValue(safeGet(excel::getGraduate, ""));
        row.createCell(3).setCellValue(safeGet(excel::getBackground, ""));
        row.createCell(4).setCellValue(safeGet(excel::getMajorName, ""));
        row.createCell(5).setCellValue(safeGet(excel::getProductName, ""));
        createNumericCell(row, 6, excel.getTotalFee(), numberCellStyle); // 数量字段

        row.createCell(7).setCellValue(safeGet(excel::getUnderstand, ""));
        row.createCell(8).setCellValue(safeGet(excel::getPayStatus, ""));
        row.createCell(9).setCellValue(safeGet(excel::getPayTime, ""));
        row.createCell(10).setCellValue(safeGet(excel::getRefundStatus, ""));
        row.createCell(11).setCellValue(safeGet(excel::getOrderType, ""));


    }

    // 辅助方法：安全地获取对象属性，提供默认值以防 null
    private static <T> T safeGet(Supplier<T> getter, T defaultValue) {
        T value = getter.get();
        return value != null ? value : defaultValue;
    }
    //新出库表合计行
    private void generateNewDeliveryTotalRow(Sheet sheet, List<OrderExcel> excelList, CellStyle numberCellStyle, int rowNum) {
        if (excelList.isEmpty()) return;
        // 创建合计行
        Row totalRow = sheet.createRow(rowNum);

        // 0 和 1 列合并，赋值为“合计”
        sheet.addMergedRegion(new CellRangeAddress(rowNum, rowNum, 0, 1)); // 合并 0 和 1 列
        Cell cell = totalRow.createCell(0);
        cell.setCellValue("合计:");


        sheet.addMergedRegion(new CellRangeAddress(rowNum, rowNum, 2, 5));
        Cell motheCell = totalRow.createCell(1);
        motheCell.setCellValue(""); // 假设 getTime 返回 Date 类型，可以转换为字符串
        sheet.addMergedRegion(new CellRangeAddress(rowNum, rowNum, 7, 11));
        Cell additionalInfoCell = totalRow.createCell(2);
        additionalInfoCell.setCellValue(""); // 假设 getTime 返回 Date 类型，可以转换为字符串

//        // 合并 4, 5, 6, 7 列
//        sheet.addMergedRegion(new CellRangeAddress(rowNum, rowNum, 9, 14)); // 合并 4 到 7 列
//        Cell additionalInfoCell = totalRow.createCell(2);  // 4 列是起始单元格
//        additionalInfoCell.setCellValue("寄出产品 相关合同金额:");
//
////        BigDecimal kcAmount = excelList.stream()
////                .map(ShipmentsExcel::getAmount)
////                .filter(Objects::nonNull)
////                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal kcAmount = excelList.stream()
                .map(orderExcel -> {
                    BigDecimal amount = orderExcel.getTotalFee();
                    return amount;
                })
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
// 设置合计值
        createNumericCell(totalRow, 6, kcAmount, numberCellStyle); // 订单金额

    }



    //单行标题头设置
    private void addUsingTitleRow(Sheet sheet, CellStyle titleCellStyle, String name, Integer wide) {
        // 创建一个单元格样式对象
        // 设置行高
        Row titleRow = sheet.createRow(0);
        titleRow.setHeightInPoints(25); // 设置行高
        // 合并列 0 到 18, 赋值为 "销售内勤操作"
        Cell titleCell1 = titleRow.createCell(0);
        titleCell1.setCellValue(name);
        sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, wide)); // 合并
        titleCell1.setCellStyle(titleCellStyle);
        titleCellStyle.setAlignment(HorizontalAlignment.CENTER); // 设置水平居中
        titleCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 设置垂直居中
    }


    /**
     * 公共方法
     */

    //设置宽度
    private void adjustColumnWidths(Sheet sheet, int headerRowNum, String[] headers) {
        // 计算每列的最小宽度（考虑标题）
        int[] columnWidths = new int[headers.length];
        for (int i = 0; i < headers.length; i++) {
            columnWidths[i] = Math.max(columnWidths[i], calculateCellWidth(headers[i]));
        }

        // 遍历所有行，找到每列最大值
        for (Row row : sheet) {
            if (row.getRowNum() >= headerRowNum) { // 忽略标题行之前的行
                for (Cell cell : row) {
                    if (cell.getColumnIndex() < columnWidths.length) {
                        String cellValue = getCellValueAsString(cell);
                        columnWidths[cell.getColumnIndex()] = Math.max(columnWidths[cell.getColumnIndex()], calculateCellWidth(cellValue));
                    }
                }
            }
        }

        // 设置每列的宽度
        for (int i = 0; i < columnWidths.length; i++) {
            sheet.setColumnWidth(i, columnWidths[i] * 280); // Excel中的单位是字符宽度乘以256
        }
    }

    //给所有生成的数据行设置行高。
    private void setRowHeightForDataRows(Sheet sheet, int startRow, int endRow, short height) {
        // 确保行高在 short 的范围内
        if (height < Short.MIN_VALUE || height > Short.MAX_VALUE) {
            throw new IllegalArgumentException("Row height out of range: " + height);
        }

        // 遍历从 startRow 到 endRow 之间的所有行（包括边界）
        for (int rowNum = startRow; rowNum <= endRow; rowNum++) {
            Row row = sheet.getRow(rowNum);
            if (row != null) { // 检查行是否存在
                row.setHeightInPoints(height);
            }
        }
    }

    //设置边框
    private void addBordersToAllCells(Sheet sheet, CellStyle cellStyle) {
        // 创建边框样式
        // 设置四个方向的边框（上、下、左、右）
        cellStyle.setBorderTop(BorderStyle.THIN);
        cellStyle.setBorderBottom(BorderStyle.THIN);
        cellStyle.setBorderLeft(BorderStyle.THIN);
        cellStyle.setBorderRight(BorderStyle.THIN);

        // 获取工作表的最大行数和列数
        int rowCount = sheet.getLastRowNum(); // 获取工作表的最大行索引
        int colCount = 0;

        // 遍历所有行
        for (int rowIndex = 0; rowIndex <= rowCount; rowIndex++) {
            Row row = sheet.getRow(rowIndex);
            if (row == null) {
                row = sheet.createRow(rowIndex); // 如果该行为空，则创建空行
            }

            // 获取该行的最大列数
            colCount = Math.max(colCount, row.getLastCellNum());

            // 遍历当前行的所有列
            for (int colIndex = 0; colIndex < colCount; colIndex++) {
                Cell cell = row.getCell(colIndex);
                if (cell == null) {
                    cell = row.createCell(colIndex); // 如果该单元格为空，则创建空单元格
                }

                // 为每个单元格设置边框样式
                cell.setCellStyle(cellStyle);
            }
        }
    }

    // 辅助方法：计算字符串显示宽度
    private int calculateCellWidth(String value) {
        if (value == null || value.isEmpty()) return 10; // 默认最小宽度

        // 假设每个字符占用大约7个像素宽，这里只是一个估计值
        // 实际上，Excel中字体和字符宽度可能有所不同，因此这只是一个近似值
        // 如果需要更精确的结果，可以使用字体度量工具或测试特定字体下的字符宽度
        FontMetrics metrics = new FontMetrics(new java.awt.Font("宋体", java.awt.Font.PLAIN, 10)) {
            @Override
            public int stringWidth(String str) {
                return (int) (str.length() * 7.5); // 每个字符平均7.5像素宽
            }
        };
        return metrics.stringWidth(value) / 7 + 3; // 添加一些额外的空间7+2
    }

    // 辅助方法：获取单元格的字符串表示形式
    private String getCellValueAsString(Cell cell) {
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    return String.valueOf((long) cell.getNumericCellValue());
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            default:
                return "";
        }
    }

    // 合并单元格的辅助方法
    private void mergeColumns(Sheet sheet, int startRow, int endRow, int colIndex) {
        sheet.addMergedRegion(new CellRangeAddress(startRow, endRow, colIndex, colIndex));
        Row row = sheet.getRow(startRow);
        Cell cell = row.getCell(colIndex);
        if (cell != null) {
            cell.setCellStyle(cell.getSheet().getWorkbook().createCellStyle());
            cell.getCellStyle().setAlignment(HorizontalAlignment.CENTER); // 合并单元格时居中对齐
            cell.getCellStyle().setVerticalAlignment(VerticalAlignment.CENTER);
        }
    }

    // 更新后的创建标题行方法
    private void createHeaderCells(Row headerRow, String[] headers) {
        for (int i = 0; i < headers.length; i++) {
            Cell cell = headerRow.createCell(i);
            cell.setCellValue(headers[i]);
        }
    }



    // 使用 CellStyle 格式化 BigDecimal 并处理 null 值
    private static void createNumericCell(Row row, int columnIndex, BigDecimal value, CellStyle numberCellStyle) {
        Cell cell = row.createCell(columnIndex);
        cell.setCellStyle(numberCellStyle);
        if (value != null) {
            cell.setCellValue(value.doubleValue());
        }
    }


}
